import logging
import os
from datetime import datetime
from logging.handlers import TimedRotatingFileHandler
from typing import Any, Dict, Optional

from pydantic import BaseModel, Field
from pythonjsonlogger import jsonlogger
from pythonjsonlogger.json import JsonFormatter
from sqlalchemy import Column, DateTime, Integer, String, Text, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker


# 定义日志数据模型
class LogEntry(BaseModel):
    level: str
    name: str
    lineno: int
    filename: str
    message: str
    timestamp: datetime = Field(default_factory=datetime.now)
    extra: Optional[Dict[str, Any]] = None


# SQLAlchemy 数据库模型
SQLBase = declarative_base()


class LogRecord(SQLBase):
    __tablename__ = "log_records"

    id = Column(Integer, primary_key=True, autoincrement=True)
    level = Column(String(10), nullable=False, index=True)
    name = Column(String(50), nullable=False)
    lineno = Column(Integer)
    filename = Column(String(100))
    message = Column(Text, nullable=False)
    timestamp = Column(DateTime, default=datetime.now, index=True)
    extra_data = Column(Text, nullable=True)


# 数据库处理器
class DatabaseHandler(logging.Handler):

    def __init__(self, db_url="sqlite:///logs/app_logs.db"):
        super().__init__()
        self.engine = create_engine(db_url)
        SQLBase.metadata.create_all(self.engine)
        self.Session = sessionmaker(bind=self.engine)

    def emit(self, record):
        # 避免在日志处理过程中出现异常导致应用崩溃
        try:
            # 提取额外数据
            extra_data = {
                k: v
                for k, v in record.__dict__.items()
                if k not in logging.LogRecord("", 0, "", 0, "", (
                ), None).__dict__
            }

            # 创建日志记录
            log_entry = LogEntry(level=record.levelname,
                                 name=record.name,
                                 lineno=record.lineno,
                                 filename=record.filename,
                                 message=record.getMessage(),
                                 timestamp=datetime.fromtimestamp(
                                     record.created),
                                 extra=extra_data if extra_data else None)

            # 将日志写入数据库
            session = self.Session()
            try:
                db_log = LogRecord(level=log_entry.level,
                                   name=log_entry.name,
                                   lineno=log_entry.lineno,
                                   filename=log_entry.filename,
                                   message=log_entry.message,
                                   timestamp=log_entry.timestamp,
                                   extra_data=str(log_entry.extra)
                                   if log_entry.extra else None)
                session.add(db_log)
                session.commit()
            except Exception as e:
                session.rollback()
                print(f"Error saving log to database: {e}")
            finally:
                session.close()
        except Exception as e:
            print(f"Error in database handler: {e}")


def setup_logger(name=None, log_dir='logs'):
    # 确保日志目录存在
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)

    # 使用传入的名称或默认使用模块名
    logger = logging.getLogger(name or __name__)

    # 避免重复添加处理器
    if logger.handlers:
        return logger

    logger.setLevel(logging.DEBUG)

    # 定义不同级别的日志文件
    log_levels = {
        'debug': (logging.DEBUG, 7),
        'info': (logging.INFO, 30),
        'warning': (logging.WARNING, 30),
        'error': (logging.ERROR, 90)
    }

    # 日志格式
    formatter = jsonlogger.JsonFormatter(
        fmt=
        '%(asctime)s %(levelname)s %(name)s %(lineno)d %(filename)s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
        json_ensure_ascii=False)

    # 为每个级别创建处理器
    for level_name, (level, backup_count) in log_levels.items():
        file_handler = TimedRotatingFileHandler(filename=os.path.join(
            log_dir, f'{level_name}.log'),
                                                when='midnight',
                                                interval=1,
                                                backupCount=backup_count,
                                                encoding='utf-8')
        file_handler.setLevel(level)
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)

    # 添加控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)

    # 控制台使用更易读的格式
    console_formatter = logging.Formatter(
        '%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')
    console_handler.setFormatter(console_formatter)
    logger.addHandler(console_handler)

    # 添加数据库处理器
    db_handler = DatabaseHandler()
    db_handler.setLevel(logging.INFO)  # 只将INFO及以上级别的日志存入数据库
    logger.addHandler(db_handler)

    return logger


if __name__ == '__main__':
    logger = setup_logger()

    logger.debug("调试信息")
    logger.info("普通信息")
    logger.warning("警告信息")
    logger.error("错误信息", extra={'traceback': 'traceback信息', "a": 1})
